package totalFileSize;

import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class ConcurrentTotalFielSizeWLatch {
	
	private ExecutorService service;
	final private AtomicLong pendingFileVisits = new AtomicLong();
	final private AtomicLong totalSize = new AtomicLong();
	final private CountDownLatch latch = new CountDownLatch(1);
	
	private void updateTotalSizeOfFileInDir(final File file) {
		long fileSize = 0;
		if (file.isFile()) {
			fileSize = file.length();
		} else {
			final File[] children = file.listFiles();
			if (children != null) {
				for (final File child : children) {
					if (child.isFile()) {
						fileSize += child.length();
					} else {
						pendingFileVisits.incrementAndGet();
						service.execute(new Runnable() {
							
							@Override
							public void run() {
								// TODO Auto-generated method stub
								updateTotalSizeOfFileInDir(child);
							}
						});
					}
				}
			}
		}
		totalSize.addAndGet(fileSize);
		if (pendingFileVisits.decrementAndGet() == 0) {
			latch.countDown();
		}
	}

	private long getTotalSizeOfFile(final String fileName) throws InterruptedException {
		service = Executors.newFixedThreadPool(8);
		pendingFileVisits.incrementAndGet();
		try {
			updateTotalSizeOfFileInDir(new File(fileName));
//			latch.await(100, TimeUnit.SECONDS);
			latch.await();
			return totalSize.longValue();
		} finally {
			service.shutdown();
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		final long start = System.nanoTime();
		final long total = new ConcurrentTotalFielSizeWLatch().getTotalSizeOfFile("/home");
		final long end = System.nanoTime();
		System.out.println("Total Size: " + total);
		System.out.println("Time taken: " + (end - start)/1.0e9);
	}
	
}
